use std::{
    sync::{Arc, Mutex},
    thread::{self, JoinHandle, ThreadId},
};

use dfs::{
    inode::DfsInode,
    seq_file::{SeqFileCreateOptions, SeqFileOperation},
    seq_println,
};
use rcu::rcu_info;

use super::SiminkManage;

struct ManageWorkerPoolInner {
    pool: Mutex<Vec<JoinHandle<()>>>,
    // 主线程 id
    main: ThreadId,
    // rcu 线程 id
    rcu: ThreadId,
}

pub(crate) struct ManageWorkerPool {
    pool: Arc<ManageWorkerPoolInner>,
}

impl ManageWorkerPool {
    pub(crate) fn new(parent: Arc<DfsInode>, rcu: ThreadId) -> Self {
        let data = Arc::new(ManageWorkerPoolInner {
            pool: Mutex::new(Vec::new()),
            main: thread::current().id(),
            rcu,
        });
        SeqFileCreateOptions::new()
            .read(true)
            .name("thread_info")
            .create_seq_file(parent, data.clone())
            .unwrap();

        Self { pool: data }
    }
}

impl SiminkManage {
    /// 保存线程句柄
    ///
    /// 保存程序中创建的每一个线程句柄, 用于在程序退出时验证程序中所有程序退出
    #[allow(clippy::missing_panics_doc)]
    pub fn push_worker(&self, handle: JoinHandle<()>) {
        let mut lock = self.worker_pool.pool.pool.lock().unwrap();
        lock.push(handle);
    }

    /// 等待所有工作线程退出
    #[allow(clippy::missing_panics_doc)]
    pub fn worker_join(&self) {
        // 仅允许主线程调用
        assert_eq!(thread::current().id(), self.worker_pool.pool.main);

        loop {
            let this;
            {
                let mut lock = self.worker_pool.pool.pool.lock().unwrap();
                this = lock.pop();
            }
            if let Some(t) = this {
                if self.worker_pool.pool.rcu != t.thread().id() {
                    t.join().unwrap();
                }
            } else {
                break;
            }
        }
    }
}

impl SeqFileOperation for ManageWorkerPoolInner {
    fn show(
        &self,
        m: &mut dfs::seq_file::SeqFile,
        _: &mut Box<dyn std::any::Any + Send>,
    ) -> monitor::MonResult<()> {
        let main = rcu_info(&self.main).unwrap();
        seq_println!(m, "name: simink, threadid: {}, {}", self.main.as_u64(), main);
        let lock = self.pool.lock().unwrap();
        for join in lock.iter() {
            let thread = join.thread();
            let id = thread.id();
            let rcu = rcu_info(&id).unwrap();
            seq_println!(m, "name: {}, threadid: {}, {}", thread.name().unwrap(), id.as_u64(), rcu);
        }
        Ok(())
    }
}
